#include "sbrbtree.h"
#include "sbalance.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/** bug fix:
  1. when has mutiple same key, insert same key not correct lead to core dump,
		fix when same, so need find leaf node, instead of selecting the same key's left node simply
  **/
struct rb_root sb_timer_tree = RB_ROOT;

struct sb_event * sb_timer_search(struct rb_root *root, unsigned long timeout_time)
{
        struct rb_node *node = root->rb_node;
	struct sb_event *event = NULL;

        while (node) {
                event = container_of(node, struct sb_event, node);

                if (timeout_time < event->timeout_time)
                        node = node->rb_left;
                else if (timeout_time > event->timeout_time)
                        node = node->rb_right;
                else
                        return event;
        }

        return NULL;
}

int sb_timer_insert(struct rb_root *root, struct sb_event *event)
{
        struct rb_node **new = &(root->rb_node), *parent = NULL;

        /* Figure out where to put new node */
        while (*new) {
                struct sb_event *this = container_of(*new, struct sb_event, node);

                parent = *new;
                if (event->timeout_time < this->timeout_time)
                        new = &((*new)->rb_left);
                else if (event->timeout_time > this->timeout_time)
                        new = &((*new)->rb_right);
                else 
                        new = &((*new)->rb_left);
        }

        /* Add new node and rebalance tree. */
        rb_link_node(&event->node, parent, new);
        rb_insert_color(&event->node, root);

        return 0;
}

/* api to outside use */
void sb_timer_push_event(struct sb_event *event)
{
	if (event->in_timer_set)	return;

	sb_timer_insert(&sb_timer_tree, event);
	event->in_timer_set = 1;
}

void sb_timer_pop_event(struct sb_event *ev)
{
	if (!ev->in_timer_set)	return;

	rb_erase(&ev->node, &sb_timer_tree);
	ev->in_timer_set = 0;
}

unsigned long sb_find_lastest_timer()
{
	struct rb_node *node = NULL;
	struct sb_event *timer = NULL;
	
	node = rb_first(&sb_timer_tree); 
	if (node == NULL)
		return 1000;	/* no timer */

	timer = rb_entry(node, struct sb_event, node);
	if (timer->timeout_time < sb_current_msec_time()) {
		return 	sb_current_msec_time() - timer->timeout_time;
	}
	else 
		return 0;
}

void sb_process_expire_timer(struct sb_cycle_env *env)
{
	struct rb_node *node = NULL;
	struct sb_event *event = NULL;
	
	unsigned long current_time =  sb_current_msec_time();

	for (;;) {
		node = rb_first(&sb_timer_tree); 
		if (node == NULL) break;

		event = container_of(node, struct sb_event, node);
		if (event->timeout_time <= current_time) {
			/* timeout process */
			event->timeout = 1;
			if (event->handler) {
				(void)event->handler(env, event);
				DebugOutput("timeout!!!");
			}
			
			/* possible in 'handler' delete the node */
			if (event->in_timer_set) {
				rb_erase(node, &sb_timer_tree);
			}
			event->in_timer_set = 0;
		}
		else {
			break;
		}
	}
}

int sb_timer_is_empty()
{
	return (rb_first(&sb_timer_tree) == NULL);
}
